﻿#region Copyright information
// 
// Copyright © 2012-2013 Yongkee Cho. All rights reserved.
// 
// This code is a part of the SubnetworkToolkit and governed under the terms of the
// GNU Lesser General  Public License (LGPL) version 2.1 which accompanies this distribution.
// For more information on the LGPL, please visit http://bol.codeplex.com/license.
// 
// - Filename: Program.cs
// - Author: Yongkee Cho
// - Email: yongkeecho@outlook.com
// - Date Created: 2013-01-30 2:55 PM
// - Last Modified: 2013-01-30 3:21 PM
// 
#endregion
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Linq;
using BOL.Algorithms.Optimization.EvolutionaryAlgorithms;
using BOL.IO;
using BOL.Linq.Descriptive;
using CommandLine;
using SubnetworkToolkit.IO;

namespace SubnetworkToolkit.GeneticAlgorithmSearch
{
    static class Program
    {
        static void Main(string[] args)
        {
            var options = new Options();

            try
            {
                // parse arguments
                var parser = new CommandLineParser(new CommandLineParserSettings(Console.Error));
                parser.ParseArguments(args, options);

                if (args.Length == 0 || args[0] == "-h")
                    Console.Error.Write(options.GetUsage());
                else
                {
                    //var pattern = options.Pattern;
                    var networkFile = options.NetworkFile;
                    var statisticsFile = options.StatisticsFile;
                    var threshold = options.Threshold;
                    var outputFile = options.OutputFile;
                    var isVerbose = options.IsVerbose == 1;
                    var top = options.Top;

                    // reads network file
                    var sr = new StreamReader(networkFile);
                    var dictionary = new Dictionary<int, List<int>>();
                    while (!sr.EndOfStream)
                    {
                        var line = sr.ReadLine();
                        if (line != null)
                        {
                            var tmp =
                                line.Split(new[] {'\t'}, StringSplitOptions.RemoveEmptyEntries).Select(Int32.Parse).
                                    ToList();
                            dictionary.Add(tmp[0], tmp.Skip(1).Select(x => x).ToList());
                        }
                    }
                    sr.Close();

                    // reads statistics file
                    var dtr = new DelimitedTextReader(statisticsFile, ",");
                    var statistics = dtr.Read().ToDictionary(line => Int32.Parse(line[0]), line => Double.Parse(line[1]));
                    statistics = statistics.Where(x => dictionary.ContainsKey(x.Key)).ToDictionary(x => x.Key, x => x.Value);
                    dtr.Close();

                    // generate max possible number of nodes;
                    var seed = options.Seed == 0 ? (int)DateTime.Now.Ticks : options.Seed;
                    var minNodes = options.MinNodes;
                    var maxNodes = options.MaxNodes;
                    var populationSize = options.PopulationSize;
                    var numberOfElites = options.NumberOfElites;
                    var selectionMethod = options.SelectionMethod;
                    var crossoverRate = options.CrossoverRate;
                    var mutationRate = options.MutationRate;
                    var allowRedundancy = options.AllowRedundancy == 1;
                    var doParallel = options.DoParallel == 1;
                    var k = options.K;
                    var stationarySolution = options.Stationary;
                    var bypass = options.Bypass.Select(Int32.Parse).ToList();
                    var forcing = options.IsForcing == 1;

                    // PreProcessing
                    //var preProcess = new PreProcessing(new Random(seed), dictionary, statistics, minNodes, maxNodes,
                    //                                   10000);

                    //var means = new double[100] { 1.877289248, 1.805736856, 1.791182358, 1.782842571, 1.776628957, 1.773325255, 1.773552289, 1.768503638, 1.770155503, 1.76730729, 1.764056741, 1.761307543, 1.760434445, 1.759185565, 1.759903617, 1.761157387, 1.762659623, 1.762469354, 1.76210004, 1.764025879, 1.764194066, 1.7639803, 1.764627078, 1.765734326, 1.766039695, 1.766531163, 1.766646115, 1.767008601, 1.767434633, 1.766762921, 1.767799985, 1.768372875, 1.768457917, 1.768155993, 1.767878341, 1.767695415, 1.768296698, 1.767953064, 1.768196995, 1.768425916, 1.768835586, 1.769183394, 1.769417772, 1.769416209, 1.769677738, 1.769394186, 1.769383012, 1.768995432, 1.768984961, 1.769436936, 1.76964448, 1.769539541, 1.769503233, 1.76962301, 1.769548372, 1.769706383, 1.769946702, 1.769598868, 1.7694425, 1.769647561, 1.769441713, 1.769604514, 1.769893731, 1.769731288, 1.769852967, 1.769660194, 1.769339688, 1.769159728, 1.769697059, 1.769495708, 1.769608038, 1.769317656, 1.76930075, 1.769323833, 1.769097671, 1.76917143, 1.76937472, 1.76949316, 1.769487269, 1.769393493, 1.769754474, 1.769769131, 1.770191095, 1.770070352, 1.769856044, 1.76964811, 1.769636108, 1.769693645, 1.769464091, 1.769438418, 1.769460741, 1.769350979, 1.769409373, 1.769210939, 1.768943451, 1.768882877, 1.768801612, 1.768950554, 1.768878989, 1.768992046 };
                    //var stdDevs = new double[100] { 1.492389884, 1.010762887, 0.823609268, 0.714447573, 0.639893777, 0.586349298, 0.545818738, 0.508625468, 0.478257523, 0.454038864, 0.432369372, 0.412806371, 0.39758706, 0.383788587, 0.369817704, 0.358303278, 0.349790031, 0.340008463, 0.331248651, 0.323164573, 0.314991915, 0.309368653, 0.303654963, 0.29792796, 0.292188999, 0.286779041, 0.281716911, 0.2767176, 0.272274358, 0.267406439, 0.263748804, 0.259684096, 0.254916971, 0.252144612, 0.247677635, 0.24427932, 0.241020553, 0.237661721, 0.234719081, 0.231639009, 0.228989275, 0.226383648, 0.223996194, 0.221775332, 0.219039202, 0.216530769, 0.214021384, 0.211787031, 0.210013066, 0.208524962, 0.206469993, 0.204117673, 0.20212695, 0.200008879, 0.198206012, 0.196415545, 0.194900317, 0.193084926, 0.191187412, 0.189547045, 0.188158854, 0.186873219, 0.185967274, 0.184743936, 0.183397348, 0.182079691, 0.180289685, 0.17877899, 0.177565172, 0.17583111, 0.174492389, 0.173321734, 0.171766339, 0.170954097, 0.169990813, 0.168963724, 0.167704973, 0.166581313, 0.165452408, 0.164588873, 0.163491872, 0.162105564, 0.161191658, 0.160324977, 0.159173744, 0.15805071, 0.157081134, 0.156266767, 0.155513001, 0.154769034, 0.15396624, 0.152965892, 0.151930068, 0.151000304, 0.150181925, 0.149252053, 0.148444419, 0.14793174, 0.14715976, 0.146525297 };

                    var mean = statistics.Average(x => x.Value);
                    var stdDev = statistics.StandardDeviation(x => x.Value);

                    var ns = selectionMethod == SelectionMethod.Tournament
                                 ? new GeneticSearch(
                                       new Random(seed),
                                       dictionary,
                                       statistics,
                                       minNodes,
                                       maxNodes,
                                       populationSize,
                                       numberOfElites,
                                       k,
                                       crossoverRate,
                                       mutationRate,
                                       stationarySolution,
                                       threshold,
                                       allowRedundancy,
                                       isVerbose,
                                       doParallel,
                                       bypass,
                                       mean,
                                       stdDev,
                                       forcing
                                       )
                                 : new GeneticSearch(
                                       new Random(seed),
                                       dictionary,
                                       statistics,
                                       minNodes,
                                       maxNodes,
                                       populationSize,
                                       numberOfElites,
                                       selectionMethod,
                                       crossoverRate,
                                       mutationRate,
                                       stationarySolution,
                                       threshold,
                                       allowRedundancy,
                                       isVerbose,
                                       doParallel,
                                       bypass,
                                       mean,
                                       stdDev,
                                       forcing
                                       );

                    var subnets = ns.Optimize(top).Select((subnet, index) => new GeneSet("Subnet" + (index + 1), subnet.Mean.ToString(CultureInfo.InvariantCulture), subnet)); 

                    // create output directory
                    var gmt = new GmtWriter(outputFile, subnets);
                    gmt.Write();
                    gmt.Close();
                }
            }
            catch (Exception ex)
            {
                Console.Error.Write(ex.Message);
            }
        }
    }
}
